// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This class maintains a transport for audio and video in a Cast Streaming
// session.
// Audio, video frames and RTCP messages are submitted to this object
// and then packetized and paced to the underlying UDP socket.
//
// The hierarchy of send transport in a Cast Streaming session:
//
// CastTransport              RTP                      RTCP
// ------------------------------------------------------------------
//                      TransportEncryptionHandler (A/V)
//                      RtpSender (A/V)                   Rtcp (A/V)
//                                      PacedSender (Shared)
//                                      UdpTransport (Shared)
//
// There are objects of TransportEncryptionHandler, RtpSender and Rtcp
// for each audio and video stream.
// PacedSender and UdpTransport are shared between all RTP and RTCP
// streams.

#ifndef MEDIA_CAST_NET_CAST_TRANSPORT_IMPL_H_
#define MEDIA_CAST_NET_CAST_TRANSPORT_IMPL_H_

#include <stdint.h>

#include <memory>
#include <set>
#include <vector>

#include "base/callback.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "media/cast/common/transport_encryption_handler.h"
#include "media/cast/logging/logging_defines.h"
#include "media/cast/net/cast_transport.h"
#include "media/cast/net/cast_transport_config.h"
#include "media/cast/net/pacing/paced_sender.h"
#include "media/cast/net/rtcp/rtcp_builder.h"
#include "media/cast/net/rtcp/sender_rtcp_session.h"
#include "media/cast/net/rtp/rtp_parser.h"
#include "media/cast/net/rtp/rtp_sender.h"
#include "net/base/network_interfaces.h"

namespace media {
namespace cast {

    class UdpTransport;

    class CastTransportImpl final : public CastTransport {
    public:
        CastTransportImpl(
            base::TickClock* clock, // Owned by the caller.
            base::TimeDelta logging_flush_interval,
            std::unique_ptr<Client> client,
            std::unique_ptr<PacketTransport> transport,
            const scoped_refptr<base::SingleThreadTaskRunner>& transport_task_runner);

        ~CastTransportImpl() final;

        // CastTransport implementation for sending.
        void InitializeStream(const CastTransportRtpConfig& config,
            std::unique_ptr<RtcpObserver> rtcp_observer) final;
        void InsertFrame(uint32_t ssrc, const EncodedFrame& frame) final;

        void SendSenderReport(uint32_t ssrc,
            base::TimeTicks current_time,
            RtpTimeTicks current_time_as_rtp_timestamp) final;

        void CancelSendingFrames(uint32_t ssrc,
            const std::vector<FrameId>& frame_ids) final;

        void ResendFrameForKickstart(uint32_t ssrc, FrameId frame_id) final;

        PacketReceiverCallback PacketReceiverForTesting() final;

        // Possible keys of |options| handled here are:
        //   "pacer_target_burst_size": int
        //        - Specifies how many packets to send per 10 ms ideally.
        //   "pacer_max_burst_size": int
        //        - Specifies how many pakcets to send per 10 ms, maximum.
        //   "send_buffer_min_size": int
        //        - Specifies the minimum socket send buffer size.
        //   "disable_wifi_scan" (value ignored)
        //        - Disable wifi scans while streaming.
        //   "media_streaming_mode" (value ignored)
        //        - Turn media streaming mode on.
        // Note, these options may be ignored on some platforms.
        void SetOptions(const base::DictionaryValue& options) final;

        // CastTransport implementation for receiving.
        void AddValidRtpReceiver(uint32_t rtp_sender_ssrc,
            uint32_t rtp_receiver_ssrc) final;

        // Building and sending RTCP packet from RTP receiver implementation.
        void InitializeRtpReceiverRtcpBuilder(uint32_t rtp_receiver_ssrc,
            const RtcpTimeData& time_data) final;
        void AddCastFeedback(const RtcpCastMessage& cast_message,
            base::TimeDelta target_delay) final;
        void AddPli(const RtcpPliMessage& pli_message) final;
        void AddRtcpEvents(
            const ReceiverRtcpEventSubscriber::RtcpEvents& rtcp_events) final;
        void AddRtpReceiverReport(
            const RtcpReportBlock& rtp_receiver_report_block) final;
        void SendRtcpFromRtpReceiver() final;

    private:
        // Handle received RTCP messages on RTP sender.
        class RtcpClient;

        struct RtpStreamSession;

        FRIEND_TEST_ALL_PREFIXES(CastTransportImplTest, NacksCancelRetransmits);
        FRIEND_TEST_ALL_PREFIXES(CastTransportImplTest, CancelRetransmits);
        FRIEND_TEST_ALL_PREFIXES(CastTransportImplTest, Kickstart);
        FRIEND_TEST_ALL_PREFIXES(CastTransportImplTest, DedupRetransmissionWithAudio);

        // Resend packets for the stream identified by |ssrc|.
        // If |cancel_rtx_if_not_in_list| is true then transmission of packets for the
        // frames but not in the list will be dropped.
        // See PacedSender::ResendPackets() to see how |dedup_info| works.
        void ResendPackets(uint32_t ssrc,
            const MissingFramesAndPacketsMap& missing_packets,
            bool cancel_rtx_if_not_in_list,
            const DedupInfo& dedup_info);

        // If |logging_flush_interval| is set, this is called at approximate periodic
        // intervals.
        void SendRawEvents();

        // Called when a packet is received.
        bool OnReceivedPacket(std::unique_ptr<Packet> packet);

        // Called when a log message is received.
        void OnReceivedLogMessage(EventMediaType media_type,
            const RtcpReceiverLogMessage& log);

        // Called when a RTCP Cast message is received.
        void OnReceivedCastMessage(uint32_t ssrc,
            const RtcpCastMessage& cast_message);

        base::TickClock* const clock_; // Not owned by this class.
        const base::TimeDelta logging_flush_interval_;
        const std::unique_ptr<Client> transport_client_;
        const std::unique_ptr<PacketTransport> transport_;
        const scoped_refptr<base::SingleThreadTaskRunner> transport_task_runner_;

        // FrameEvents and PacketEvents pending delivery via raw events callback.
        // Do not add elements to these when |logging_flush_interval| is
        // |base::TimeDelta()|.
        std::vector<FrameEvent> recent_frame_events_;
        std::vector<PacketEvent> recent_packet_events_;

        // Packet sender that performs pacing.
        PacedSender pacer_;

        // Right after a frame is sent we record the number of bytes sent to the
        // socket. We record the corresponding bytes sent for the most recent ACKed
        // audio packet.
        int64_t last_byte_acked_for_audio_;

        // Packets that don't match these sender ssrcs are ignored.
        std::set<uint32_t> valid_sender_ssrcs_;

        // While non-null, global WiFi behavior modifications are in effect. This is
        // used, for example, to turn off WiFi scanning that tends to interfere with
        // the reliability of UDP packet transmission.
        std::unique_ptr<net::ScopedWifiOptions> wifi_options_autoreset_;

        // Do not initialize the |rtcp_builder_at_rtp_receiver_| if the RTP receiver
        // SSRC does not match these ssrcs. Only RTP receiver needs to register its
        // SSRC in this set.
        std::set<uint32_t> valid_rtp_receiver_ssrcs_;

        std::unique_ptr<RtcpBuilder> rtcp_builder_at_rtp_receiver_;

        // Records the initialized stream sessions on RTP sender. The sender SSRC is
        // used as key since it is unique for each RTP stream.
        using SessionMap = std::map<uint32_t, std::unique_ptr<RtpStreamSession>>;
        SessionMap sessions_;

        base::WeakPtrFactory<CastTransportImpl> weak_factory_;

        DISALLOW_COPY_AND_ASSIGN(CastTransportImpl);
    };

} // namespace cast
} // namespace media

#endif // MEDIA_CAST_NET_CAST_TRANSPORT_IMPL_H_
